
package com.borqs.music.ui.online;

import static com.borqs.music.util.MusicUtils.DownloadDefs.DOWNLOAD_INTENT_KEY_DOWNLOAD_ITEM;

import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.CheckBox;
import android.widget.ListView;

import com.borqs.music.DownloadService;
import com.borqs.music.R;
import com.borqs.music.database.CacheUtils;
import com.borqs.music.database.DBController;
import com.borqs.music.executor.MusicExecutor;
import com.borqs.music.executor.Task;
import com.borqs.music.executor.TaskAdapter;
import com.borqs.music.executor.TaskListener;
import com.borqs.music.model.DownloadItem;
import com.borqs.music.model.SongInfo;
import com.borqs.music.tasks.DeleteSongTask;
import com.borqs.music.tasks.GetSongsTask;
import com.borqs.music.tasks.UpdateOnlineFavorTask;
import com.borqs.music.ui.adapter.PersonalTrackListAdapter;
import com.borqs.music.util.MusicUtils;
import com.borqs.music.util.MyLogger;

public class PersonalMusicListActivity extends OnlineBaseActivity {
    private static MyLogger logger = MyLogger.getLogger("AbsentLocalMusicListActivity");

    private static final int MSG_GET_ONLINE_SONGS_SUCCESS = 0;
    private static final int MSG_UPDATE_LIST = 1;
    private static final int MSG_GET_ONLINE_SONGS_FAILED = 4;
    private static final int MSG_DELETE_SONG_SUCCESS = 5;
    private static final int MSG_REMOVE_FROM_MY_FAVORITE_SUCCESS = 6;
    private static final int MSG_ADD_TO_MY_FAVORITE_SUCCESS = 8;

    private static final int DIALOG_LOADING_SONGS = 10;
    private static final int DIALOG_REMOVE_FAVORITE_CONFIRM = 11;

    private static final String LAST_CACHED_SONG_TIME = "lastCahcedSongTime";
    private static final long UPDATE_CACHED_SONG_FREQUENCY = 60000; // 60 * 1000 = 1 minute

    private static List<SongInfo> mOnlineSongs;
    private static List<SongInfo> mLocalSongs;
    protected String mListType;
    private int mSelectedPosition;
    private Map<Integer, Integer> mOnlineLocalSongId;

    private List<SongInfo> mCurrentList;
    private String mCategoryKey;
    private PersonalTrackListAdapter mAdapter;
    private boolean mIsLoadingLocalSongs;
    private DBController mDBController;

    private TaskListener mTaskListener = new TaskAdapter() {
        @Override
        public void onFail(Task task) {
            logger.d("Get all song from server failed.");
            mHandler.sendEmptyMessage(MSG_GET_ONLINE_SONGS_FAILED);
            AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
                @Override
                public void run(AccountManagerFuture<Bundle> future) {
                    if(future.isCancelled()){
                        PersonalMusicListActivity.this.finish();
                    }else if(future.isDone()){
                        executeGetSongTask(true);
                    }
                }
            };
            MusicUtils.checkSessionExpired(task.getErrorReason().code,
                    PersonalMusicListActivity.this,
                    callback);
        }

        @Override
        @SuppressWarnings("unchecked")
        public void onDone(Task task) {
            logger.d("Get all song from server successfully.");
            mOnlineSongs = (List<SongInfo>) task.getResult();
            Collections.sort(mOnlineSongs, new Comparator<SongInfo>() {
                @Override
                public int compare(SongInfo s, SongInfo t) {
                    Collator myCollator = Collator.getInstance(java.util.Locale.CHINA);
                    if (myCollator.compare(s.title, t.title) < 0)
                        return -1;
                    else if (myCollator.compare(s.title, t.title) > 0)
                        return 1;
                    else
                        return 0;
                }
            });
            mHandler.sendEmptyMessage(MSG_GET_ONLINE_SONGS_SUCCESS);
        }
    };

    private Thread mLoadLocalSongsThread = new Thread() {
        public void run() {
            mLocalSongs = mDBController.queryAllSong();
            if (mLocalSongs == null) {
                mLocalSongs = new ArrayList<SongInfo>();
            }
            logger.d("Get " + mLocalSongs.size() + " local songs.");

            mIsLoadingLocalSongs = false;
        }

    };

    private Thread mGetAbsentSongThread = new Thread() {
        public void run() {
            logger.d("Start to find absent local songs.");
            mOnlineLocalSongId = new HashMap<Integer, Integer>();
            SongInfo onlineSong = null;

            for (int i = 0, n = mOnlineSongs.size(); i < n; i++) {
                onlineSong = mOnlineSongs.get(i);
                for (int j = 0, s = mLocalSongs.size(); j < s; j++) {
                    if (onlineSong.fileMd5.equals(mLocalSongs.get(j).fileMd5)) {
                        onlineSong.isNotInDevice = false;
                        mOnlineLocalSongId.put(onlineSong.id, mLocalSongs.get(j).id);

                        logger.d("song title:" + onlineSong.title + " is local : " + onlineSong.isNotInDevice);
                    }
                }
            }

            mDBController.insertAllCachedSong(mOnlineSongs, CacheUtils.CACHE_TYPE_PERSONAL_SONG);
            MusicUtils.setLongPref(PersonalMusicListActivity.this   , LAST_CACHED_SONG_TIME, System.currentTimeMillis());
        }
    };

    Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_GET_ONLINE_SONGS_SUCCESS:
                    if (mIsLoadingLocalSongs) {
                       mHandler.sendEmptyMessageDelayed(MSG_GET_ONLINE_SONGS_SUCCESS, 100);
                    } else {
                        //mGetAbsentSongThread.start();
                        for (int i = 0, n = mOnlineSongs.size(); i < n; i++) {
                            for (int j = 0, s = mLocalSongs.size(); j < s; j++) {
                                if (mOnlineSongs.get(i).fileMd5.equals(mLocalSongs.get(j).fileMd5)) {
                                    mOnlineSongs.get(i).isNotInDevice = false;
                                    //logger.d("song title:" + mOnlineSongs.get(i).title + " is local : "
                                    //        + !mOnlineSongs.get(i).isNotInDevice);
                                }
                            }
                        }
                        mDBController.insertAllCachedSong(mOnlineSongs, CacheUtils.CACHE_TYPE_PERSONAL_SONG);
                        MusicUtils.setLongPref(PersonalMusicListActivity.this,
                                LAST_CACHED_SONG_TIME, System.currentTimeMillis());

                        setListAdapter();
                        removeDialog(DIALOG_LOADING_SONGS);
                    }
                    break;
                case MSG_GET_ONLINE_SONGS_FAILED:
                    removeDialog(DIALOG_LOADING_SONGS);
                    break;
                case MSG_UPDATE_LIST:
                    mAdapter.notifyDataSetChanged();
                    break;
                case MSG_DELETE_SONG_SUCCESS:
                    mCurrentList.remove((SongInfo)msg.obj);
                    mAdapter.notifyDataSetChanged();
                    showToast(msg.arg1);
                    break;
                case MSG_REMOVE_FROM_MY_FAVORITE_SUCCESS:
                    mAdapter.notifyDataSetChanged();
                    showToast(msg.arg1);
                    break;
                case MSG_ADD_TO_MY_FAVORITE_SUCCESS:
                    mAdapter.notifyDataSetChanged();
                    showToast(msg.arg1);
                    break;
            }
        };
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        logger.d("onCreate() ...");
        super.onCreate(savedInstanceState);
        mListType = getIntent().getType();
        mDBController = DBController.getInstance(this);

        setContentView(R.layout.personal_media_list);
        MusicUtils.addNowPlayingListener(this);
        registerForContextMenu(getListView());

        if (mListType.equals(MusicUtils.TypeDefs.ONLINE_PERSONAL_TRACK)) {
            MusicUtils.initTitleBar(this, getListView(), getString(R.string.absent_local_list_title_track));
        } else if (mListType.equals(MusicUtils.TypeDefs.ONLINE_PERSONAL_FAVORITE)) {
            MusicUtils.initTitleBar(this, getListView(),getString(R.string.absent_local_list_title_favorite));
        } else if (mListType.equals(MusicUtils.TypeDefs.ONLINE_PERSONAL_ALBUM)) {
            mCategoryKey = getIntent().getStringExtra("album");
            MusicUtils.initTitleBar(this, getListView(), getString(R.string.absent_local_list_title_album));
        } else if (mListType.equals(MusicUtils.TypeDefs.ONLINE_PERSONAL_ARTIST)) {
            mCategoryKey = getIntent().getStringExtra("artist");
            MusicUtils.initTitleBar(this, getListView(), getString(R.string.absent_local_list_title_artist));
        }

        updateCahcedSong();

        IntentFilter f = new IntentFilter();
        f.addAction(DownloadService.ACTION_TASK_DOWNLOAD_DONE);
        registerReceiver(mDownloadTaskReceiver, f);
    }

    private void executeGetSongTask(boolean showProcessDialog) {
        if (showProcessDialog) {
            showDialog(DIALOG_LOADING_SONGS);
        }
        GetSongsTask task = new GetSongsTask(mTaskListener, mTicket);
        MusicExecutor.getInstance().execute(task);
    }

    private void setListAdapter() {
        logger.d("setListAdapter() ...");
        List<SongInfo> list = null;
        if (mListType.equals(MusicUtils.TypeDefs.ONLINE_PERSONAL_TRACK)) {
            list = mDBController.queryAllCahcedSong(CacheUtils.CACHE_TYPE_PERSONAL_SONG);
        } else if (mListType.equals(MusicUtils.TypeDefs.ONLINE_PERSONAL_FAVORITE)) {
            list = mDBController.queryCachedSongByFavor(CacheUtils.CACHE_TYPE_PERSONAL_SONG);
        } else if (mListType.equals(MusicUtils.TypeDefs.ONLINE_PERSONAL_ALBUM)) {
            list = mDBController.queryCachedSongByAlbum(mCategoryKey, CacheUtils.CACHE_TYPE_PERSONAL_SONG);
        } else if (mListType.equals(MusicUtils.TypeDefs.ONLINE_PERSONAL_ARTIST)) {
            list = mDBController.queryCachedSongByArtist(mCategoryKey, CacheUtils.CACHE_TYPE_PERSONAL_SONG);
        }

        if (mCurrentList == null) {
            mCurrentList = list;
        } else {
            mCurrentList.clear();
            mCurrentList.addAll(list);
        }

        if (mAdapter == null) {
            mAdapter = new PersonalTrackListAdapter(this, mCurrentList);
            mAdapter.setActivity(this);
            setListAdapter(mAdapter);
            logger.d("set list adapter ...");
        } else {
            logger.d("Do not need to reset adapter, only update list view.");
            mAdapter.notifyDataSetChanged();
        }
    }

    private void updateCahcedSong() {
        logger.d("updateCachedSong() ...");
        if (mDBController.queryCachedSongSize(CacheUtils.CACHE_TYPE_PERSONAL_SONG) > 0) {
            long lastUpdateTime = MusicUtils.getLongPref(this, LAST_CACHED_SONG_TIME, 0);
            if (System.currentTimeMillis() - lastUpdateTime > UPDATE_CACHED_SONG_FREQUENCY) {
                logger.d("Cached song time out, re-cache all songs background.");
                executeGetSongTask(false);
                mIsLoadingLocalSongs = true;
                mLoadLocalSongsThread.start();
            }
            setListAdapter();
        } else {
            logger.d("Re-cache all songs from server.");
            executeGetSongTask(true);
            mIsLoadingLocalSongs = true;
            mLoadLocalSongsThread.start();
        }
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        playsong(mCurrentList, position);
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mDownloadTaskReceiver);
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        AlertDialog dialog = null;
        switch (id) {
            case DIALOG_LOADING_SONGS:
                dialog = new ProgressDialog(this);
                dialog.setIcon(android.R.drawable.ic_dialog_info);
                dialog.setTitle(R.string.dialog_loading_songs_title);
                dialog.setMessage(getString(R.string.dialog_loading_songs_message));
                dialog.setCancelable(true);
                return dialog;
            case DIALOG_REMOVE_FAVORITE_CONFIRM:
                LayoutInflater inflate = LayoutInflater.from(this);
                final View dialogContent = inflate.inflate(R.layout.remove_favorite_dialog, null);
                final SongInfo song = mCurrentList.get(mSelectedPosition);
                dialog = new AlertDialog.Builder(this).setView(dialogContent).setTitle(
                        R.string.dialog_remove_favorite_title).setIcon(
                        android.R.drawable.ic_dialog_alert).setPositiveButton(android.R.string.ok,
                        new OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                if (((CheckBox) dialogContent.findViewById(R.id.delete_chkbox))
                                        .isChecked()) {
                                    removeOnlineSong(song);
                                } else {
                                    removeFavorite(song);
                                }
                            }
                        }).setNegativeButton(android.R.string.cancel, null).create();
                return dialog;
            default:
                break;
        }
        return super.onCreateDialog(id);
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        menu.add(0, DOWNLOAD_SONG, 0, R.string.download_song);

        AdapterContextMenuInfo mi = (AdapterContextMenuInfo) menuInfo;
        mSelectedPosition = mi.position;
        if (MusicUtils.TypeDefs.ONLINE_PERSONAL_ARTIST.equals(mListType)) {
        } else if (MusicUtils.TypeDefs.ONLINE_PERSONAL_ALBUM.equals(mListType)) {
        } else{
            menu.add(0, DELETE_ITEM, 0, R.string.delete_item);
            menu.setHeaderTitle(mCurrentList.get(mSelectedPosition).title);
        }
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case DOWNLOAD_SONG: {
                SongInfo song = mCurrentList.get(mSelectedPosition);
                downloadSingleSong(song, true);
                return true;
            }
            case DELETE_ITEM: {
                SongInfo song = mCurrentList.get(mSelectedPosition);
                removeOnlineSong(song);
                return true;
            }
        }
        return super.onContextItemSelected(item);
    }

    private BroadcastReceiver mDownloadTaskReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (DownloadService.ACTION_TASK_DOWNLOAD_DONE.equals(action)) {
                DownloadItem item = intent.getParcelableExtra(DOWNLOAD_INTENT_KEY_DOWNLOAD_ITEM);
                markSongAsLocal(item.getId());
            }
        }
    };

    private void markSongAsLocal(long id) {
        for (SongInfo s : mCurrentList) {
            if (id == s.id) {
                s.isNotInDevice = false;
                if (null != mAdapter) {
                    logger.d("mark " + s.title + " as local song");
                    mAdapter.notifyDataSetChanged();
                }
                break;
            }
        }
    }

    private void removeOnlineSong(final SongInfo song) {
        Task deleteSongTask = new DeleteSongTask(new TaskAdapter() {
            @Override
            public void onFail(Task task) {
                showToast(R.string.delete_failed);
            }
            @Override
            public void onDone(Task task) {
                mDBController.deleteCachedSong(song.id, CacheUtils.CACHE_TYPE_PERSONAL_SONG);
                Message msg = mHandler.obtainMessage(MSG_DELETE_SONG_SUCCESS);
                msg.arg1 = R.string.delete_success;
                msg.obj = task.getResult();
                mHandler.sendMessage(msg);
            }
        },song , mTicket);
        MusicExecutor.getInstance().execute(deleteSongTask);
    }

    private void removeFavorite(final SongInfo song) {
        UpdateOnlineFavorTask updateOnlineFavor = new UpdateOnlineFavorTask(new TaskAdapter() {
            @Override
            public void onFail(Task task) {
                showToast(R.string.update_favorite_failed);
            }
            @Override
            public void onDone(Task task) {
                song.isFavorite = false;
                mDBController.updateCachedSongFavor(song.isFavorite,
                        song.fileMd5, CacheUtils.CACHE_TYPE_PERSONAL_SONG);
                Message msg = mHandler.obtainMessage(MSG_REMOVE_FROM_MY_FAVORITE_SUCCESS);
                msg.arg1 = R.string.remove_from_myfavorite_msg;
                mHandler.sendMessage(msg);

                if (!song.isNotInDevice) {
                    List<Long> favorIDs = MusicUtils
                            .loadFavoriteSongIds(PersonalMusicListActivity.this);
                    long localSongID = DBController.getInstance(PersonalMusicListActivity.this)
                            .findSongIdByMD5(song.fileMd5);
                    if (favorIDs.remove(localSongID)) {
                        MusicUtils.saveFavoriteQueue(PersonalMusicListActivity.this, favorIDs);
                    }
                }
            }
        }, mTicket, String.valueOf(song.id), false);
        MusicExecutor.getInstance().execute(updateOnlineFavor);
    }

    private void addFavorite(final SongInfo song) {
        UpdateOnlineFavorTask updateOnlineFavor = new UpdateOnlineFavorTask(new TaskAdapter() {
            @Override
            public void onFail(Task task) {
                showToast(R.string.update_favorite_failed);
            }
            @Override
            public void onDone(Task task) {
                song.isFavorite = true;
                mDBController.updateCachedSongFavor(song.isFavorite,
                        song.fileMd5, CacheUtils.CACHE_TYPE_PERSONAL_SONG);
                Message msg = mHandler.obtainMessage(MSG_ADD_TO_MY_FAVORITE_SUCCESS);
                msg.arg1 = R.string.add_into_myfavorite_msg;
                mHandler.sendMessage(msg);

                if (!song.isNotInDevice) {
                    List<Long> favorIDs = MusicUtils.loadFavoriteSongIds(PersonalMusicListActivity.this);
                    long localSongID = DBController.getInstance(PersonalMusicListActivity.this).findSongIdByMD5(song.fileMd5);
                    if (localSongID > 0 && !favorIDs.contains(localSongID)) {
                        favorIDs.add(localSongID);
                        MusicUtils.saveFavoriteQueue(PersonalMusicListActivity.this, favorIDs);
                    }
                }
            }
        }, mTicket, String.valueOf(song.id), true);
        MusicExecutor.getInstance().execute(updateOnlineFavor);
    }

    public void updateFavoriteStatus(SongInfo song) {
        if (song == null) {
            return;
        }

        if (song.isFavorite) {
            removeFavorite(song);
        } else {
            addFavorite(song);
        }
    }
}
